package com.example.rule;


import com.example.rule.core.Facts;
import com.example.rule.core.Rule;
import com.example.rule.core.Rules;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Jason - Chusifeng
 * @version 1.0.0
 * @ClassName RuleEngine.java
 * @PackageName com\welab\vb\payment\transaction\rule\RuleEngine.java
 * @Description rule engine
 * @createTime 2022年10月10日 09:29:26
 */
@Slf4j
@Data
public class RuleEngine {
    /**
     * 如果检测到一个通过了，自动跳过其他
     */
    private boolean skipIfOnePass;

    /**
     * 如果检测途中异常，直接返回出错
     */
    private boolean ifExceptionThrow;

    /**
     * 所有规则中最大值
     */
    private boolean takeMax;

    public RuleEngine() {
        this.skipIfOnePass = false;
        this.ifExceptionThrow = false;
    }




    public BigDecimal start(Facts facts, Rules rules) {
        List<BigDecimal> bigDecimals = new ArrayList<>(rules.size());
        if (rules.isEmpty()) {
            log.warn("No rules registered! Nothing to apply");
            throw new RuntimeException("No rules registered! Nothing to apply") ;
        }
        for (Rule rule : rules) {
            boolean evaluate = rule.evaluate(facts);
            if (evaluate) {
                try {
                   bigDecimals.add(rule.execute(facts));
                } catch (Exception e) {
                    if (ifExceptionThrow) {
                        log.error("execute error",e);
                        throw new RuntimeException(e);
                    }
                }
            }
            if (!bigDecimals.isEmpty() &&skipIfOnePass) {
                break;
            }
        }
        if (takeMax){
           return bigDecimals.stream().sorted(Comparator.comparing(BigDecimal::longValue).reversed()).collect(Collectors.toList()).get(0);
        }
        //没有任何符合的，则表示免费
        if (bigDecimals.isEmpty()) {
            return BigDecimal.ZERO;
        }
        return bigDecimals.get(0);
    }
}
